﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static Easily.frmGraphicProgrammer;

namespace Easily
{
    public partial class frmConfigHardCon : Form
    {
        //用列表存储所有下拉框 用于执行统一处理
        List<ComboBox> hardCboxs = new List<ComboBox>();
        Hard_Connect hard_Connect;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="isCreateCode">[2021/3/13]第一次加载 需要确认后生成代码 true则生成代码</param>
        /// 添加这个参数 解决了无法访问已释放的对象这个问题
        /// 问题原因：确认按钮事件触发之后，该窗体被关闭，所以加入一个变量 控制确认事件的点击
        /// 确认事件只出现在打开工程（此时需要读取上一次存档，并生成代码）
        public frmConfigHardCon(bool isCreateCode)
        {
            InitializeComponent();
            //将所有需要统一处理的下拉框加入hardCboxs列表
            hardCboxs.Add(cbox1);
            hardCboxs.Add(cbox2);
            hardCboxs.Add(cbox3);
            hardCboxs.Add(cbox4);
            hardCboxs.Add(cbox5);
            hardCboxs.Add(cbox7);
            //J6、J8、J9只能用于固定的外设
            cbox6.Items.Add("四按扭模块");
            cbox8.Items.Add("数码管模块");
            cbox9.Items.Add("小车");
            cbox6.SelectedItem = "四按扭模块";
            cbox8.SelectedItem = "数码管模块";
            cbox9.SelectedItem = "小车";
            //[2021/2/9] 该窗体构造时 IconGeneralArr还没有加载完毕
            //所以以下代码有问题
            //启动程序后自动加载frm窗体内容
            //并确认 确保生成正确代码
            if (isCreateCode)
            {
                frmConfigHardCon_Init();
                btn_confirm_Click(new object(), new EventArgs());
            }

        }

        List<string> hardNames = new List<string>();

        /// <summary>
        /// 初始化 设置配置终端中的选项
        /// </summary>
        private void frmConfigHardCon_Init()
        {
            hard_Connect = Globaldefine.FrmParent.ActivedrmGraphicFlow.hard_Connect;
            //if (hardCboxs != null) return;
            //hardCboxs = new List<ComboBox>();
            //TODO ComboBox的设置有问题 每次加载未选择的下拉框也会有值 概率情况
            hardNames.Clear();//清空所有硬件 
            //[2021/1/31]清空下拉框所有选项
            foreach (ComboBox c in hardCboxs)
            {
                c.Items.Clear();
            }
            foreach (GeneralIcon icon in Globaldefine.FrmParent.ActivedrmGraphicFlow.IconGeneralArr)
            {
                //【2021/4/19】如果智能拐杖-NB模块，需要传入多个参数
                if(icon.ModuleName== "智能拐杖-NB")
                {
                    cbox1.Items.Add("触发式开关");
                    cbox2.Items.Add("加速度传感器");
                    cbox3.Items.Add("蜂鸣器");
                    cbox4.Items.Add("电机");
                    cbox5.Items.Add("超声波传感器");
                    cbox7.Items.Add("超声波传感器1");
                    cbox1.SelectedItem = hard_Connect.J1 = "触发式开关";
                    cbox2.SelectedItem = hard_Connect.J2 = "加速度传感器";
                    cbox3.SelectedItem = hard_Connect.J3 = "蜂鸣器";
                    cbox4.SelectedItem = hard_Connect.J4 = "电机";
                    cbox5.SelectedItem = hard_Connect.J5 = "超声波传感器";
                    //[2021/1/31]Combox6、8、9都有默认值，以后要取消默认值，在此处设置即可，
                    //并注意在hard_connect中添加JCar
                    //cbox6.SelectedItem = Globaldefine.FrmParent.GraphicProgrammerOfForm.hard_Connect.J6;
                    cbox7.SelectedItem = hard_Connect.J7 = "超声波传感器1";
                    Globaldefine.loadConfig.dicHard_USB["超声波传感器1"] = "";
                    SetUSBNum();
                }
                else if(icon.ModuleName == "温度-NB")
                {
                    cbox1.Items.Add("温度传感器");
                    cbox1.SelectedItem = hard_Connect.J1 = "温度传感器";
                    Globaldefine.loadConfig.dicHard_USB["温度传感器"] = "";
                    SetUSBNum();
                }
                else 
                    //【2021/1/30】如果是外设 就需要配置终端
                    if (Globaldefine.loadConfig.notInner_device.Contains(icon.ModuleName))
                    {
                        //这四个外设 只能用于J1、J3、J4
                        if (icon.ModuleName == "人体红外" || icon.ModuleName == "碰撞检测" || icon.ModuleName == "触发式开关"
                        || icon.ModuleName == "红外循迹")
                        {
                            cbox1.Items.Add(icon.IconName);
                            cbox3.Items.Add(icon.IconName);
                            cbox4.Items.Add(icon.IconName);
                        }
                        else if (icon.ModuleName == "声音传感器" || icon.ModuleName == "温度传感器")
                        {
                            cbox2.Items.Add(icon.IconName);
                            cbox5.Items.Add(icon.IconName);
                            cbox7.Items.Add(icon.IconName);
                        }
                        else if(icon.ModuleName=="加速度传感器")
                        {
                            cbox1.Items.Add(icon.IconName);
                            cbox2.Items.Add(icon.IconName);
                        }
                        else if(icon.ModuleName== "可调亮度小灯")
                        {
                            if(!cbox4.Items.Contains(icon.IconName))
                                cbox4.Items.Add(icon.IconName);
                        }
                        //else if(icon.ModuleName == "高精温度传感器")
                        //{
                        //    if (!cbox7.Items.Contains(icon.IconName))
                        //        cbox7.Items.Add(icon.IconName);
                        //}
                        else
                            hardNames.Add(icon.IconName);
                    }

            }
            hardNames.Add("");

            //根据hardNames存储的名字 为所有下拉框添加items
            foreach (string s in hardNames)
            {
                foreach (ComboBox c in hardCboxs)
                {
                    //[2021/3/22]
                    if (!c.Items.Contains(s))
                        c.Items.Add(s);
                }
            }
            cbox1.SelectedItem = hard_Connect.J1;
            cbox2.SelectedItem = hard_Connect.J2;
            cbox3.SelectedItem = hard_Connect.J3;
            cbox4.SelectedItem = hard_Connect.J4;
            cbox5.SelectedItem = hard_Connect.J5;
            //[2021/1/31]Combox6、8、9都有默认值，以后要取消默认值，在此处设置即可，
            //并注意在hard_connect中添加JCar
            //cbox6.SelectedItem = Globaldefine.FrmParent.GraphicProgrammerOfForm.hard_Connect.J6;
            cbox7.SelectedItem = hard_Connect.J7;
            //cbox8.SelectedItem = Globaldefine.FrmParent.GraphicProgrammerOfForm.hard_Connect.J8;
            //cbox9.SelectedItem = Globaldefine.FrmParent.GraphicProgrammerOfForm.hard_Connect.JCar;
        }

        /// <summary>
        /// 配置终端窗体加载时 初始化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmConfigHardCon_Load(object sender, EventArgs e)
        {
            if (Globaldefine.FrmParent.ActivedrmGraphicFlow.IconGeneralArr == null) return;
            frmConfigHardCon_Init();
        }

        private  void btn_confirm_Click(object sender, EventArgs e)
        {
            
            //【2021/01/28理解 每个工程会覆盖上次json中的硬件配置，所以这样保存应该不太合理？】
            //保存至json文件中
            //现在切换保存到xml文件即工程prj文件中 原json文件中弃用
            if (cbox1.SelectedItem != null)
                hard_Connect.J1 = cbox1.SelectedItem.ToString();
            if (cbox2.SelectedItem != null)
                hard_Connect.J2 = cbox2.SelectedItem.ToString();
            if (cbox3.SelectedItem != null)
                hard_Connect.J3 = cbox3.SelectedItem.ToString();
            if (cbox4.SelectedItem != null)
                hard_Connect.J4 = cbox4.SelectedItem.ToString();
            if (cbox5.SelectedItem != null)
                hard_Connect.J5 = cbox5.SelectedItem.ToString();
            //[2021/1/31]Combox6、8都有默认值，以后要取消默认值，在此处设置即可
            //if (cbox6.SelectedItem != null)
            //    Globaldefine.FrmParent.GraphicProgrammerOfForm.hard_Connect.J6 = cbox6.SelectedItem.ToString();
            if (cbox7.SelectedItem != null)
                hard_Connect.J7 = cbox7.SelectedItem.ToString();
            //if (cbox8.SelectedItem != null)
            //    Globaldefine.FrmParent.GraphicProgrammerOfForm.hard_Connect.J8 = cbox8.SelectedItem.ToString();
            SetUSBNum();
            ////更新dicHard_USB字典中的硬件连接对应情况
            //for (int i = 0 ;i < hardCboxs.Count;i++)
            //{
            //    if(hardCboxs[i].SelectedItem != null && hardCboxs[i].SelectedItem.ToString() != "")
            //    {
            //        Globaldefine.loadConfig.dicHard_USB[hardCboxs[i].SelectedItem.ToString()] = "J" + (i + 1).ToString();
            //    }
            //}
            //更新可扩展硬件控件的连接情况
            foreach (GeneralIcon icon in Globaldefine.FrmParent.ActivedrmGraphicFlow.IconGeneralArr)
            {
                foreach(string s in hardNames)
                {
                    //每次配置完硬件后 会重新生成代码 而之前数码管是属于要配置硬件的 因此还是会进入frmConfig这个窗体的方法
                    //这就导致最终生成的save不正确 这里的补救办法是在config.json中将数码管模块的hard_type直接置空
                    //"人体红外" || v.Value.name == "碰撞检测" || v.Value.name == "触发式开关"
                    //【修改2021/1/28 添加“红外循迹”】
                    if (s == icon.info.name|| "人体红外"== icon.info.name || "碰撞检测" == icon.info.name || 
                        "触发式开关" == icon.info.name || "红外循迹" == icon.info.name || "声音传感器" == icon.info.name
                        || "温度传感器" == icon.info.name || "加速度传感器" == icon.info.name || "智能拐杖-NB" == icon.info.name)
                    {
                        icon.GeneralIconSetting = new frmConfig(icon);
                    }
                }
            }
            //重新生成代码并保存
            Globaldefine.FrmParent.ActivedrmGraphicFlow.CreateCode();
            Globaldefine.FrmParent.ActivedrmGraphicFlow.SavePro(Globaldefine.FrmParent.ProjectPath + "\\" + Globaldefine.FrmParent. ProjectName);


            //关闭窗口
            this.Close();
        }

        /// <summary>
        /// 更新hard_usb 确保获取正确的控件名
        /// </summary>
        public void SetUSBNum()
        {
            if (hard_Connect.J1 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J1] = "J1";
            if (hard_Connect.J2 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J2] = "J2";
            if (hard_Connect.J3 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J3] = "J3";
            if (hard_Connect.J4 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J4] = "J4";
            if (hard_Connect.J5 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J5] = "J5";
            if (hard_Connect.J6 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J6] = "J6";
            if (hard_Connect.J7 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J7] = "J7";
            if (hard_Connect.J8 != "")
                Globaldefine.loadConfig.dicHard_USB[hard_Connect.J8] = "J8";
        }

        /// <summary>
        /// 下拉框重新选择外设时 去除其他下拉框可选择项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cbox_SelectionChangeCommitted(object sender, EventArgs e)
        {
            ComboBox senderC = sender as ComboBox;//获取触发该事件的下拉框
            string oldSelect = "", newSelect = "";//保存旧选择、新选择的设备名
            newSelect = senderC.SelectedItem.ToString();//新选择就是当前下拉框所选择项
            //这里好像是用Tag来保存以前的选择项
            if(senderC.Tag != null)
               oldSelect = senderC.Tag.ToString();
            senderC.Tag = newSelect;


            //[2021/3/16] 修复配置中断 修改之后 不清空之前选项的问题
            if(hard_Connect!=null)
            {
                string usbNum = "J" + senderC.Name.ElementAt(senderC.Name.Length - 1);//获取该下拉框名中的数字，判断它对应哪一个USB口
                //若USB口不是当前修改下拉框选项的USB口 且 它没有选择该下拉框选项的选项
                if (GetPropertyName<Hard_Connect>(h => h.J1) != usbNum && hard_Connect.J1 == newSelect)
                    hard_Connect.J1 = "";
                if (GetPropertyName<Hard_Connect>(h => h.J2) != usbNum && hard_Connect.J2 == newSelect)
                    hard_Connect.J2 = "";
                if (GetPropertyName<Hard_Connect>(h => h.J3) != usbNum && hard_Connect.J3 == newSelect)
                    hard_Connect.J3 = "";
                if (GetPropertyName<Hard_Connect>(h => h.J4) != usbNum && hard_Connect.J4 == newSelect)
                    hard_Connect.J4 = "";
                if (GetPropertyName<Hard_Connect>(h => h.J5) != usbNum && hard_Connect.J5 == newSelect)
                    hard_Connect.J5 = "";
                if (GetPropertyName<Hard_Connect>(h => h.J7) != usbNum && hard_Connect.J7 == newSelect)
                    hard_Connect.J7 = "";
            }



            foreach (ComboBox c in hardCboxs)
            {
                if(c != senderC)
                {
                    c.Items.Remove(newSelect);
                    //这里的处理应该是为了让空选项排在最后
                    while (c.Items.Contains("")) c.Items.Remove("");
                    if (oldSelect != "")
                        c.Items.Add(oldSelect);
                    c.Items.Add("");
                }                
            }
        }

        public static string GetPropertyName<T>(Expression<Func<T, string>> expr)
        {
            var name = ((MemberExpression)expr.Body).Member.Name;
            return name;
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
